`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2024/03/11 21:20:16
// Design Name: 
// Module Name: arp_tx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module arp_tx#(
    //开发板MAC地址 00-11-22-33-44-55   单播mac，在应答的时候发
    parameter BOARD_MAC = 48'h00_11_22_33_44_55,
    //开发板IP地址 192.168.1.10
    parameter BOARD_IP  = {8'd192,8'd168,8'd1,8'd10},
    //目的MAC地址 ff_ff_ff_ff_ff_ff 广播mac，在请求的时候发
    parameter  DES_MAC   = 48'hff_ff_ff_ff_ff_ff,
    //目的IP地址 192.168.1.102     
    parameter  DES_IP    = {8'd192,8'd168,8'd1,8'd102}
)(
    input               clk         ,
    input               rst_n       ,
    input       [47:0]  des_mac     ,   // 从rx模块缓存着的目的mac
    input       [31:0]  des_ip      ,
    input               type        ,   // 判断为请求还是应答信号  请求:type为1，应答为0
    input       [31:0]  crc_data    ,
    input       [7:0]   crc_next    ,
    input               tx_start    ,
    output reg          gmii_tx_en  ,   // gmii发信号使能
    output reg  [7:0]   gmii_tx_data,   // gmii发数据内容
    output reg          tx_done     ,
    output reg          arp_tx_busy ,
    output reg          crc_clr     ,
    output reg          crc_en      
    );

localparam 
            IDLE     = 4'd0, 
            PRE      = 4'd1,
            SFD      = 4'd2,
            D_MAC    = 4'd3,
            S_MAC    = 4'd4,
            TYPE     = 4'd5,
            DATA     = 4'd6,
            FCS      = 4'd7;
localparam
            ETH_TYPE     = 16'h0806,// 表示arp 协议
            HD_TYPE      = 16'h0001,// 表示以太网地址
            PROTOCOL_TYPE= 16'h0800;// 表示上层协议为ip协议（要映射的协议地址类型，ARP 协议的上层协议为IP 协议，因此该协议类型为IP 协议，其值为0x0800）

// reg define
reg [3:0]   cur_state, next_state;
reg         skip_en;
reg [6:0]   cnt;

reg  [7:0]  eth_head[13:0]; //以太网首部
reg  [7:0]  arp_data[27:0]; //ARP数据 

/****************************************
                main code
****************************************/       
// 状态转移
always @(posedge clk or negedge rst_n) begin
    if(~rst_n)
        cur_state <= IDLE;
    else
        cur_state <= next_state;
end

// 状态转移条件判断
always @(*)begin
    next_state = IDLE;
    case (cur_state)
        IDLE: begin
            if(skip_en)
                next_state = PRE;
            else
                next_state = IDLE; 
        end
        PRE: begin
            if(skip_en)
                next_state = SFD;
            else
                next_state = PRE; 
        end
        SFD: begin
            if(skip_en)
                next_state = D_MAC;
            else
                next_state = SFD; 
        end
        D_MAC: begin
            if(skip_en)
                next_state = S_MAC;
            else
                next_state = D_MAC; 
        end
        S_MAC: begin
            if(skip_en)
                next_state = TYPE;
            else
                next_state = S_MAC; 
        end
        TYPE: begin
            if(skip_en)
                next_state = DATA;
            else
                next_state = TYPE; 
        end
        DATA: begin
            if(skip_en)
                next_state = FCS;
            else
                next_state = DATA; 
        end
        FCS: begin
            if(skip_en)
                next_state = IDLE;
            else
                next_state = FCS; 
        end
    endcase
end

// 状态输出
always @(posedge clk or negedge rst_n) begin
    if(~rst_n)begin
        skip_en         <= 1'd0;
        gmii_tx_en      <= 1'd0;
        gmii_tx_data    <= 8'd0;
        tx_done         <= 1'd0;
        cnt             <= 7'd0;
        crc_clr         <= 1'd0;
        crc_en          <= 1'd0;
        arp_tx_busy     <= 1'd0;
        //以太网帧头 
        eth_head[0] <= DES_MAC[47:40];      //目的MAC地址
        eth_head[1] <= DES_MAC[39:32];
        eth_head[2] <= DES_MAC[31:24];
        eth_head[3] <= DES_MAC[23:16];
        eth_head[4] <= DES_MAC[15:8];
        eth_head[5] <= DES_MAC[7:0];        
        eth_head[6] <= BOARD_MAC[47:40];    //源MAC地址
        eth_head[7] <= BOARD_MAC[39:32];    
        eth_head[8] <= BOARD_MAC[31:24];    
        eth_head[9] <= BOARD_MAC[23:16];    
        eth_head[10] <= BOARD_MAC[15:8];    
        eth_head[11] <= BOARD_MAC[7:0];     
        eth_head[12] <= ETH_TYPE[15:8];     //以太网帧类型
        eth_head[13] <= ETH_TYPE[7:0];      
        //ARP数据                           
        arp_data[0] <= HD_TYPE[15:8];       //硬件类型
        arp_data[1] <= HD_TYPE[7:0];
        arp_data[2] <= PROTOCOL_TYPE[15:8]; //上层协议类型
        arp_data[3] <= PROTOCOL_TYPE[7:0];
        arp_data[4] <= 8'h06;               //硬件地址长度,6
        arp_data[5] <= 8'h04;               //协议地址长度,4
        arp_data[6] <= 8'h00;               //OP,操作码 8'h01：ARP请求 8'h02:ARP应答
        arp_data[7] <= 8'h01;
        arp_data[8] <= BOARD_MAC[47:40];    //发送端(源)MAC地址
        arp_data[9] <= BOARD_MAC[39:32];
        arp_data[10] <= BOARD_MAC[31:24];
        arp_data[11] <= BOARD_MAC[23:16];
        arp_data[12] <= BOARD_MAC[15:8];
        arp_data[13] <= BOARD_MAC[7:0];
        arp_data[14] <= BOARD_IP[31:24];    //发送端(源)IP地址
        arp_data[15] <= BOARD_IP[23:16];
        arp_data[16] <= BOARD_IP[15:8];
        arp_data[17] <= BOARD_IP[7:0];
        arp_data[18] <= DES_MAC[47:40];     //接收端(目的)MAC地址
        arp_data[19] <= DES_MAC[39:32];
        arp_data[20] <= DES_MAC[31:24];
        arp_data[21] <= DES_MAC[23:16];
        arp_data[22] <= DES_MAC[15:8];
        arp_data[23] <= DES_MAC[7:0];  
        arp_data[24] <= DES_IP[31:24];      //接收端(目的)IP地址
        arp_data[25] <= DES_IP[23:16];
        arp_data[26] <= DES_IP[15:8];
        arp_data[27] <= DES_IP[7:0];
    end
    else begin
        skip_en <= 1'd0;
        tx_done <= 1'd0;
        crc_clr <= 1'd0;
        case (next_state)
            IDLE:begin
                gmii_tx_data <= 8'd0;
                if(tx_start)begin
                    arp_tx_busy <= 1'd1;
                    gmii_tx_en <= 1'd1;
                    skip_en <= 1'd1;
                    if(type)begin
                        //以太网帧头 
                        eth_head[0] <= DES_MAC[47:40];      //广播mac
                        eth_head[1] <= DES_MAC[39:32];
                        eth_head[2] <= DES_MAC[31:24];
                        eth_head[3] <= DES_MAC[23:16];
                        eth_head[4] <= DES_MAC[15:8];
                        eth_head[5] <= DES_MAC[7:0];             
                        eth_head[12] <= ETH_TYPE[15:8];     //以太网帧类型
                        eth_head[13] <= ETH_TYPE[7:0]; 

                        arp_data[7] <= 8'h01;// arp请求
                        arp_data[18] <= DES_MAC[47:40];     //接收端(目的)MAC地址
                        arp_data[19] <= DES_MAC[39:32];
                        arp_data[20] <= DES_MAC[31:24];
                        arp_data[21] <= DES_MAC[23:16];
                        arp_data[22] <= DES_MAC[15:8];
                        arp_data[23] <= DES_MAC[7:0];  
                        arp_data[24] <= DES_IP[31:24];      //接收端(目的)IP地址
                        arp_data[25] <= DES_IP[23:16];
                        arp_data[26] <= DES_IP[15:8];
                        arp_data[27] <= DES_IP[7:0];
                    end
                    else begin
                        arp_data[7] <= 8'h02;// arp应答

                        eth_head[0] <= des_mac[47:40];
                        eth_head[1] <= des_mac[39:32];
                        eth_head[2] <= des_mac[31:24];
                        eth_head[3] <= des_mac[23:16];
                        eth_head[4] <= des_mac[15:8];
                        eth_head[5] <= des_mac[7:0];  
                        arp_data[18] <= des_mac[47:40];
                        arp_data[19] <= des_mac[39:32];
                        arp_data[20] <= des_mac[31:24];
                        arp_data[21] <= des_mac[23:16];
                        arp_data[22] <= des_mac[15:8];
                        arp_data[23] <= des_mac[7:0];  
                        arp_data[24] <= des_ip[31:24];
                        arp_data[25] <= des_ip[23:16];
                        arp_data[26] <= des_ip[15:8];
                        arp_data[27] <= des_ip[7:0];
                    end
                end
            end
            PRE:begin
                cnt <= cnt + 7'd1;
                gmii_tx_data <= 8'h55;
                if(cnt == 7'd6)begin
                    cnt <= 7'd0;
                    skip_en <= 1'd1;
                end
            end
            SFD:begin
                gmii_tx_data <= 8'hd5;
                skip_en <= 1'd1;
            end 
            D_MAC:begin
                cnt <= cnt + 7'd1;
                if(type) // 请求
                    case (cnt)
                        7'd0: begin
                            crc_en <= 1'd1;
                            gmii_tx_data <= DES_MAC[47:40];
                        end
                        7'd1: gmii_tx_data <= DES_MAC[39:32]; 
                        7'd2: gmii_tx_data <= DES_MAC[31:24]; 
                        7'd3: gmii_tx_data <= DES_MAC[23:16]; 
                        7'd4: gmii_tx_data <= DES_MAC[15: 8]; 
                        7'd5: begin
                            gmii_tx_data <= DES_MAC[ 7: 0];
                            skip_en <= 1'd1;
                            cnt <= 7'd0;
                        end 
                    endcase
                else    // 应答
                    case (cnt)
                        7'd0: begin // case1 没加 crc_en... 导致在应答的时候crc校验失败
                            crc_en <= 1'd1;
                            gmii_tx_data <= eth_head[0]; 
                        end
                        7'd1: gmii_tx_data <= eth_head[1]; 
                        7'd2: gmii_tx_data <= eth_head[2]; 
                        7'd3: gmii_tx_data <= eth_head[3]; 
                        7'd4: gmii_tx_data <= eth_head[4]; 
                        7'd5: begin
                            gmii_tx_data <= eth_head[5];
                            skip_en <= 1'd1;
                            cnt <= 7'd0;
                        end 
                    endcase
            end
            S_MAC: begin
                cnt <= cnt + 7'd1;
                case (cnt)
                    7'd0: gmii_tx_data <= eth_head[6]; 
                    7'd1: gmii_tx_data <= eth_head[7]; 
                    7'd2: gmii_tx_data <= eth_head[8]; 
                    7'd3: gmii_tx_data <= eth_head[9]; 
                    7'd4: gmii_tx_data <= eth_head[10]; 
                    7'd5: begin
                        gmii_tx_data <= eth_head[11];
                        skip_en <= 1'd1;
                        cnt <= 7'd0;
                    end 
                endcase
            end
            TYPE: begin
                cnt <= cnt + 7'd1;
                case (cnt)
                    7'd0: gmii_tx_data <= eth_head[12];  
                    7'd1: begin
                        gmii_tx_data <= eth_head[13];
                        skip_en <= 1'd1;
                        cnt <= 7'd0;
                    end  
                endcase
            end   
            DATA: begin
                cnt <= cnt + 7'd1;
                case (cnt)
                    7'd0:  gmii_tx_data <= arp_data[0];
                    7'd1:  gmii_tx_data <= arp_data[1];
                    7'd2:  gmii_tx_data <= arp_data[2];
                    7'd3:  gmii_tx_data <= arp_data[3];
                    7'd4:  gmii_tx_data <= arp_data[4];// 硬件地址长度为6byte （mac地址长度）
                    7'd5:  gmii_tx_data <= arp_data[5];// 协议地址长度为4byte （ip地址长度）
                    7'd6:  gmii_tx_data <= arp_data[6];// 请求 0001
                    7'd7:  gmii_tx_data <= arp_data[7];
                    7'd8:  gmii_tx_data <= arp_data[8];
                    7'd9:  gmii_tx_data <= arp_data[9];
                    7'd10: gmii_tx_data <= arp_data[10];
                    7'd11: gmii_tx_data <= arp_data[11];
                    7'd12: gmii_tx_data <= arp_data[12];
                    7'd13: gmii_tx_data <= arp_data[13];
                    7'd14: gmii_tx_data <= arp_data[14]; 
                    7'd15: gmii_tx_data <= arp_data[15]; 
                    7'd16: gmii_tx_data <= arp_data[16]; 
                    7'd17: gmii_tx_data <= arp_data[17]; 
                    7'd18: gmii_tx_data <= arp_data[18];
                    7'd19: gmii_tx_data <= arp_data[19];
                    7'd20: gmii_tx_data <= arp_data[20];
                    7'd21: gmii_tx_data <= arp_data[21];
                    7'd22: gmii_tx_data <= arp_data[22];
                    7'd23: gmii_tx_data <= arp_data[23];
                    7'd24: gmii_tx_data <= arp_data[24]; 
                    7'd25: gmii_tx_data <= arp_data[25]; 
                    7'd26: gmii_tx_data <= arp_data[26]; 
                    7'd27: gmii_tx_data <= arp_data[27];
                    7'd28: gmii_tx_data <= 8'd0;
                    7'd45:begin
                        cnt <= 7'd0;
                        skip_en <= 1'd1;
                    end                                         
                endcase
            end
            FCS:begin
                cnt <= cnt + 7'd1;
                case (cnt)
                    7'd0: begin
                        crc_en <= 1'd0;
                        gmii_tx_data <= {~crc_next[0], ~crc_next[1], ~crc_next[2],~crc_next[3],
                                 ~crc_next[4], ~crc_next[5], ~crc_next[6],~crc_next[7]};
                    end
                    7'd1: gmii_tx_data <= {~crc_data[16], ~crc_data[17], ~crc_data[18],
                                 ~crc_data[19], ~crc_data[20], ~crc_data[21], 
                                 ~crc_data[22],~crc_data[23]};  
                    7'd2: gmii_tx_data <= {~crc_data[8], ~crc_data[9], ~crc_data[10],
                                 ~crc_data[11],~crc_data[12], ~crc_data[13], 
                                 ~crc_data[14],~crc_data[15]}; 
                    7'd3: gmii_tx_data <= {~crc_data[0], ~crc_data[1], ~crc_data[2],~crc_data[3],
                                 ~crc_data[4], ~crc_data[5], ~crc_data[6],~crc_data[7]};

                    7'd4: begin
                        gmii_tx_data <= 8'd0;
                        skip_en <= 1'd1;
                        tx_done <= 1'd1;
                        arp_tx_busy <= 1'd0;
                        cnt <= 7'd0;
                        crc_clr <= 1'd1;
                        gmii_tx_en <= 1'd0;
                    end  
                endcase
            end      
        endcase
    end
end
endmodule
